home *** CD-ROM | disk | FTP | other *** search
- >From stinglai@bureau.World.GOV Tue Jun 5 08:50:55 1990
- From: stinglai@bureau.World.GOV (Stinglai Ka'abi)
- Newsgroups: alt.mud
- Subject: Beginner's guide to MUF programming
- Keywords: MUD Muck MUF forth Atlantis and a partridge in a pear tree
- Date: 5 Jun 90 09:19:45 GMT
- Reply-To: blojo@ocf.berkeley.edu
- Distribution: alt
-
-
- [ Updated August 10th, 1990, by ChupChup for the release of TinyMUCK 2.2. ]
-
- Zen in the Art of the Towers of Hanoi
- (or The Basics of MUF in 10 megs or less.)
-
-
- This is an introduction to MUF, a dialect/subset of forth used to do really
- really neat things with TinyMuck 2.2. This intro was designed to be read
- before any of the other MUF information; it (hopefully) should supply you
- with a fair idea of what MUF is all about. It's written at a non-programming-
- stud level, all the better for understanding.
-
-
- All MUF programs work by performing operations on a stack.
-
- For all you non-programmer types, a stack is just a tool used to store
- information. Information is manipulated by "pushing" things onto the
- stack and "popping" things off. The last thing you've placed on a stack
- is always the next thing you would take off if you tried; it's like
- piling objects on top of each other, when the only thing you can remove
- >from the pile is the thing on top. For example, if you were to push the
- number 23, then push the number 42, and then pop a value off the stack,
- you would get 42. If you were to pop another value off the stack after this,
- you would get 23. If you were to try and pop another value, you would get
- an error, since the stack would now be empty. (This is a "stack underflow.")
-
- The basic procedural unit in MUF is called the word. A word is simply a
- sequence of instructions. In program text, a word always starts with a
- colon, then the word's name. A semicolon marks the end of a word.
- For example:
-
- : detonate_explosives
- (text of word here)
- ;
-
- would define a word called detonate_explosives.
-
- Parentheses are used to delineate program comments; everything inside comments
- is ignored by the computer. The detonate_explosives word above, if run
- as shown, would do absolutely nothing.
-
- Indentation in MUF is arbitrary and serves to make the program more readable
- to people.
-
-
- In MUF, there are three types of constant values: integers, strings, and
- database references. Each of these types is stored and retrieved from the
- stack as a single unit (The string "Hello, Sailor!", for example, would be
- stored on the stack in its entirety: "Hello, Sailor!"; it would not be stored
- byte-by-byte or word-by-word or in any other such silly way.)
- To push a constant onto the stack, you only need to state its value. The
- following is a completely legitimate procedure:
-
- : pointless_word
- "Old Man"
- "I'm"
- 37
- "What?"
- 37
- "Not old!"
- ;
-
- However, run by itself, it wouldn't do anything visible to the user. It would,
- however, create a stack which looks like this:
-
- ("Old Man" "I'm" 37 "What?" 37 "Not old!")
-
- In the above stack, "Old Man" is the value on the bottom. "Not old!" is the
- value on top of the stack, and would be the next value retrieved.
-
- Placement of values on the same line of a program is arbitrary. Since each
- value represents something being put on a stack, the word
-
- : example
- "Semprini?"
- "All right, wot's all this then!"
- ;
-
- is the same as:
-
- :example
- "Semprini?" "All right, wot's all this then!"
- ;
-
-
- Functions which are available in the standard MUF library take values from the
- top of the stack, do things with them, and usually leave something new back
- on top of the stack. The words +, -, swap, pop, and random provide good
- examples of this and are discussed here.
-
- The + routine takes the top two integers from the stack, adds them together,
- and leaves the result on top of the stack. In order to easily describe
- what functions like this do, a certain stack notation is used: for +,
- this would be (i1 i2 -- z). What's inside those parenthesis is a sort of
- "Before and After" synopsis; the things to the left of the double-dash are
- the "before", and those to the right are the "after". (i1 i2 -- i) says that
- the function in question takes two integers away and leaves one. The letters
- used here to tell what kind of data a stack object can be are: i for integer,
- d for database object, s for string, v for variable, and x or y to mean
- something that can be more than one type.
-
- Here are short descriptions of the procedures listed above so you can get
- the hang of how they work:
-
-
- + (i1 i2 -- i)
- Adds i1 and i2 together. The word
-
- : add_some_stuff
- 2 3 +
- ;
-
- will return 5. The word
-
- : add_some_more_stuff
- 2 3 4
- 5
- + + +
- ;
-
- will return 14. When add_some_more_stuff first reaches the "+ + +" line,
- the stack looks like:
-
- (2 3 4 5).
-
- The first + changes the stack to look like:
-
- (2 3 9).
-
- The next causes:
-
- (2 12).
-
- The final plus returns:
-
- (14).
-
-
- - (i1 i2 -- i)
- Subtracts i2 from i1.
-
- : subtract_arbitrary_things
- 10 7 -
- ;
-
- will return 3 on top of the stack.
-
-
- swap (x y -- y x)
- Switches the top two things on the stack. This is useful for when you want
- to know the value of x but want to save y for later use.
-
- : swap_stuff_around
- 1 5
- 2 swap
- 3
- "Three, sir!"
- swap
- "Boom!"
- ;
-
- will, before it gets to the first swap, create a stack of (1 5 2).
- After the swap, the stack looks like (1 2 5). It then accumulates another
- 3 and a string constant, to look like (1 2 5 3 "Three, sir!") It swaps
- the last two again and adds another string, so the stack looks like:
- (1 2 5 "Three, sir!" 3 "Boom!").
-
-
- pop (x --)
- Throws away the value on top of the stack. As shown in the stack diagram, it
- returns nothing but takes something, and so decreases the stack's total size.
- Useful when you really really want to get to the next thing on the stack so bad
- you don't care what's on top. The word:
-
- : needless_popping_waste
- "Immanuel Kant"
- "Heideggar"
- pop
- "David Hume"
- "Schoppenhauer"
- "Hegel"
- pop pop
- ;
-
- would leave the stack looking like ("Immanuel Kant" "David Hume").
-
-
- random (-- i)
- Doesn't even look at the stack, but piles a really really random integer on
- top. The word:
-
- : feel_lucky_punkP
- random
- random
- random
- ;
-
- would return a stack of three random numbers.
-
-
- Because of the way the stack works, variables aren't as necessary in MUF as
- they are in other languages, but they can be used to simplify stack-handling
- operations. To declare a variable, you simply add the line "var <name>"
- at the beginning of your program. Variables are of no specific type; a
- variable which holds an integer can turn around the next second and hold
- a string if it's feeling haughty enough.
-
- The following words are important when dealing with variables:
-
- ! (x v --)
- Set variable v to hold value x. The program:
-
-
- var answer
-
- : multiply-and-store
- 6 9 *
- answer
- !
- ;
-
- will give the variable "answer" the value 42. This is the same as:
-
- : multiply-and-store
- 6 9 * answer !
- ;
-
-
- @ (v -- x)
- This word (pronounced "fetch") retrieves the value of a variable and puts it
- on the stack. You should remember this since a common mistake among beginning
- MUF programmers is to forget to put fetch symbols in their programs.
- The word
-
- garply
-
- by itself stands for the variable "garply", while the expression
-
- garply @
-
- stands for the value of that same variable. If you're familiar with Lisp, this
- is analogous to the difference between garply and (garply).
-
- The program:
-
- var biggles
- var fang
- : more_silly_manipulation
- 10 biggles !
- 24 fang !
- biggles @ fang @
- +
- ;
-
- will return the value 34 on top of the stack. The program:
-
- var biggles
- var fang
- : more_silly_manipulation
- 10 biggles !
- 24 fang !
- biggles fang +
- ;
-
- is *wrong*. For reasons I won't go into now, since this guide was written
- at the last moment and at great expense, the above word will return the
- value 7 on top of the stack.
-
-
- In MUF, there are two variables which are predefined and available for use at
- all times. These variables are "me" and "loc", where "me" holds the
- player's database reference, and loc holds the player's location's database
- reference.
-
- (Database references were mentioned before as the third type of constant, then
- sort of ignored till now. For the sake of completeness, I will introduce the
- word
-
- dbref (i -- d)
- Where i is an integer and d is a database reference, dbref converts between
- the two types. The line
-
- 2032 dbref
-
- will return item #2032 in the Muck database. This is useful since there
- are lots of functions that operate on database references that won't work
- on integers. [If you want to declare something in one of your programs as
- being a dbref instead of an integer, you should just put a # in front. For
- example, 69 means the integer 69, while #69 means object number 69. You
- could say '69 dbref' instead of '#69', but it would be a little slower and
- a little harder to read.]
-
- Me @ will return the player's item reference, while loc @ will return the
- room they are in. Trigger @ returns the item that triggered the current
- program, whether it is a player, exit, room, whatever. A useful word to
- know is:
-
- name (d -- s)
- Where d is a db reference and s is a string, name returns the name of item
- x.
-
-
- Now that you know about me @, another Muck function becomes useful. Its
- synopsis is:
-
- notify (d s --)
- When d is a player, notify prints string s out to user d. The program
-
- : warn
- me @
- "There is someone behind the next column waiting to jump you."
- notify
- ;
-
- would print said message on the user's screen.
-
-
- Before you can really start writing neat stuff in Muck, there are two more
- things you should know about. One is = and the other is the "if/then" setup.
-
- = (i1 i2 -- i)
- Returns 1 if integer i1 is equal to integer i2, otherwise returns 0.
-
- : nonequals
- 2 3 =
- ;
-
- returns 0.
-
- If/then could be written up with a synopsis, but it would be sort of
- complicated and probably a lie also. The way it works is this: If
- pulls an item off the stack. If the item is 0, it skips over the
- program after the IF and resumes execution at the THEN. If the item is not
- 0, the program will execute everything in between.
-
- The naming of this construction as if/then can be somewhat confusing. It
- certainly doesn't work quite like the if/then of normal languages, and the
- THEN actually being called THEN is sort of confusing. As nearly as I can
- tell, if/then is a sort of forth-creators' joke. It does not mean
- "IF the previous is true THEN do this." like it does in most languages.
- Rather, it means "IF the previous is true do this; THEN go on with the rest
- of the program." Remarkably silly.
- The word:
-
- : word
- 2 3 =
- if me @ "Your computer is broken!" notify
- then me @ "Done executing this word." notify
- ;
-
- will always print "Done executing this word." to the user, and will print
- "Your computer is broken!" if something is really screwy with the math and
- it actually thinks 2 = 3. Getting a bit more sophisticated, one can write
- something like:
-
- : word_up
- "Your computer works fine."
- 2 3 =
- if pop
- "Your computer is broken. Sorry. Truth hurts."
- then
- me @ swap notify
- ;
- When word_up is called, "Your computer works fine." gets put on the stack.
- If your computer actually works, 2 is *not* equal to 3, so that right after
- the = the stack looks like:
-
- ("Your computer works fine." 0)
-
- The IF reads the 0 and skips all the way down to the THEN.
- The SWAP in the last line is used since the NOTIFY word wants its
- parameters in the opposite order of where they would be.
-
- If your computer is broken, right after the =, the stack looks like:
-
- ("Your computer works fine." 1)
-
- The IF reads this 1 and decides to keep executing. It then gets to the POP
- which gets rid of the filthy lie about well-working computers and replaces
- it with the painful truth.
-
-
- *SAMPLE PROGRAM*
-
- Ok, so you've been reading this whole thing so far, and you really want to
- use this stuff to do something interesting. The following program does
- something interesting, and uses the function
-
- strcat (s1 s2 -- s)
- Concatenate strings s1 and s2, returning the result.
-
- it also uses
-
- location (d -- d')
- Takes db reference d and returns d', the db reference for its location.
-
- and
-
- dup (x -- x x)
- Duplicate the top of the stack.
-
- and
-
- dbcmp (d1 d2 -- )
- Works just like =, except operates on db references instead of integers.
-
-
- : far_vision
- #2032 (2032 is Celia's object number. )
- dup (Make 2 copies; we're about to use 1. )
- name (Celia might change her name in the future, so)
- (instead of using "Celia" here we just look up)
- (her name. )
-
- " is currently in "
- strcat (Attach name to sentence so far )
- swap (Flip the sentence back so we can get at)
- (Celia's dbref again. )
-
- (Celia's dbref is now at top of stack. )
-
- location (Where is Celia? )
- name (What is the name of the place she is in?)
- "." strcat strcat
-
- me @ swap notify (Tell the player where Celia is.)
-
- #2055 (Celia's hardsuit is #2055. )
- location
- #2032 (Celia again )
- dbcmp (Has she got her hardsuit with her?)
- if me @ "Watch out-- she's wearing her hardsuit!" notify then
- ;
-
-
- Note that this program uses no variables (except for the universally
- defined ME variable.)
-
-
- In Muck, this program would be attached to, say, a homing device or a magic
- staff. Now, if Boomer ever wants to find Celia, he can, and he'll even know
- if she's defenseless or she's got her armor.
-
- Without the comments and spaced out like you might see normally, this program
- looks like:
-
- : far_vision
- #2032 dup
- name " is currently in " strcat
- swap location name
- "." strcat strcat (Now we know where she is.)
-
- me @ swap notify
-
- #2055 location
- #2032 dbcmp
- if me @ "Watch out-- she's wearing her hardsuit!" notify
- then
- ;
-
-
- Words can also be called by other words; to do this, you treat your other
- words just like library functions when you use them. When you have more
- than one word in the same program, the word which is listed *last* is
- the one executed, and all the ones listed before it are subroutines. The
- above program could be rewritten:
-
- : celia-identity
- #2032
- ;
-
- : far_vision
- celia-identity dup
- name " is currently in " strcat
- swap location name
- "." strcat strcat (Now we know where she is.)
-
- me @ swap notify
-
- #2055
- location celia-identity dbcmp (Using celia-identity and spacing the )
- (commands like this makes this bit a )
- (little easier to understand. )
-
- if me @ "Watch out-- she's wearing her hardsuit!" notify
- then
- ;
-
-
- Oodles and oodles of other neat MUF library routines are available, too
- numerous to be detailed in an introduction such as this. A complete list,
- as well as sample code, is available from such spiffy ftp sites as
- prince.white.toronto.edu and belch.berkeley.edu.
-
- If you're interested in seeing more sample code, write to me for
- program listings for the Pan Galactic Gargle Blaster, walkie-talkies,
- and several useful library routines.
-
- Stinglai "Two Sheds" Ka'abi
- Mail to: blojo@ocf.berkeley.edu
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- "We are too proud to fight." --Woodrow Wilson 1856-1924
- "Violence never settles anything." --Genghis Khan 1162-1227
- "The mice voted to bell the cat." --Aesop c. 620-c. 560 B.C.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- Coming next week:
- "Life, the Universe, and INTERCAL:"
- A most excellent introduction to that programming language.
-
-
-
-